package com.joker.dynamic.thread.pool.sdk.config;

import com.alibaba.fastjson.JSON;
import com.joker.dynamic.thread.pool.sdk.domain.DynamicThreadPoolService;
import com.joker.dynamic.thread.pool.sdk.domain.IDynamicThreadPoolService;
import com.joker.dynamic.thread.pool.sdk.domain.model.entity.ThreadPoolConfigEntity;
import com.joker.dynamic.thread.pool.sdk.domain.model.valobj.RegistryEnumVO;
import com.joker.dynamic.thread.pool.sdk.register.IRegistry;
import com.joker.dynamic.thread.pool.sdk.register.redis.RedisRegistry;
import com.joker.dynamic.thread.pool.sdk.trigger.job.ThreadPoolDataReportJob;
import com.joker.dynamic.thread.pool.sdk.trigger.listener.ThreadPoolConfigAdjustListener;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;

import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 动态配置入口
 * Created By guzq on 2024/10/19
 */
@Slf4j
@EnableConfigurationProperties(DynamicThreadPoolAutoConfigAutoProperties.class)
@EnableScheduling
public class DynamicThreadPoolAutoConfig {

    private String applicationName;

    @Bean
    public DynamicThreadPoolService dynamicThreadPoolService(ApplicationContext applicationContext, Map<String, ThreadPoolExecutor> threadPoolExecutorMap) {
        applicationName = applicationContext.getEnvironment().getProperty("spring.application.name");
        if (StringUtils.isBlank(applicationName)) {
            applicationName = "缺省的";
            log.warn("动态线程池 通过 spring.application.name 未获取到应用名称！");
        }

        for (String threadPoolKey : threadPoolExecutorMap.keySet()) {
            ThreadPoolExecutor threadPoolExecutor = threadPoolExecutorMap.get(threadPoolKey);
            int poolSize = threadPoolExecutor.getPoolSize();
            int corePoolSize = threadPoolExecutor.getCorePoolSize();
            BlockingQueue<Runnable> queue = threadPoolExecutor.getQueue();
            String queueName = queue.getClass().getSimpleName();
            log.info("应用名称：{}，线程池名称：{}，线程池大小：{}，核心线程数：{}，队列类型：{}，队列大小：{}", applicationName, threadPoolKey, poolSize, corePoolSize, queueName, queue.size());
        }

        log.info("线程池信息：{}", JSON.toJSONString(threadPoolExecutorMap.keySet()));

        return new DynamicThreadPoolService(threadPoolExecutorMap, applicationName);
    }

    @Bean
    public RedissonClient redissonClient(DynamicThreadPoolAutoConfigAutoProperties properties) {
        Config config = new Config();
        // 编解码器
        config.setCodec(JsonJacksonCodec.INSTANCE);

        config.useSingleServer()
                .setAddress("redis://" + properties.getHost() + ":" + properties.getPort())
                .setPassword(properties.getPassword())
                .setConnectionPoolSize(properties.getPoolSize())
                .setConnectionMinimumIdleSize(properties.getMinIdleSize())
                .setConnectTimeout(properties.getConnectTimeOut())
                .setIdleConnectionTimeout(properties.getIdleTimeOut())
                .setRetryAttempts(properties.getRetryTimes())
                .setRetryInterval(properties.getRetryDelay())
                .setPingConnectionInterval(properties.getPingInterval())
                .setKeepAlive(properties.isKeepAlive());

        RedissonClient redissonClient = Redisson.create(config);
        log.info("动态线程池 注册中心（redis） 初始化完成。 {} {}", properties.getHost(), properties.getPort());
        return redissonClient;
    }

    @Bean
    public IRegistry iRegistry(RedissonClient redissonClient) {
        return new RedisRegistry(redissonClient);
    }

    @Bean
    public ThreadPoolDataReportJob threadPoolDataReportJob(IDynamicThreadPoolService iDynamicThreadPoolService, IRegistry iRegistry) {
        return new ThreadPoolDataReportJob(iDynamicThreadPoolService, iRegistry);
    }

    @Bean
    public ThreadPoolConfigAdjustListener threadPoolDataReportListener(IDynamicThreadPoolService iDynamicThreadPoolService, IRegistry iRegistry) {
        return new ThreadPoolConfigAdjustListener(iDynamicThreadPoolService, iRegistry);
    }

    /**
     * 监听 Redis 变化
     */
    @Bean(name = "dynamicThreadPoolRedisTopic")
    public RTopic threadPoolConfigAdjustListener(RedissonClient redissonClient, ThreadPoolConfigAdjustListener threadPoolConfigAdjustListener) {
        RTopic topic = redissonClient.getTopic(RegistryEnumVO.DYNAMIC_THEAD_POOL_REDIS_TOPIC.getKey() + "_" + applicationName);
        topic.addListener(ThreadPoolConfigEntity.class, threadPoolConfigAdjustListener);
        return topic;
    }

}
